using Digitalmes.Domain.Entities.Mes.Processes;

namespace Digitalmes.Application.Mes.Processes.RoutingSteps.Commands;

/// <summary>
/// 工艺路线步骤向上排序命令。
/// </summary>
public sealed record UpSortRoutingStepCommand(long RoutingStepId) : IRequest<IResult<bool>>;

internal sealed class UpSortRoutingStepCommandHandler(IRepository<ProcRoutingStep> repo) : IRequestHandler<UpSortRoutingStepCommand, IResult<bool>>
{
    public async Task<IResult<bool>> Handle(UpSortRoutingStepCommand request, CancellationToken cancellationToken)
    {
        var step = await repo.GetByIdAsync(request.RoutingStepId, cancellationToken);
        if (step == null)
        {
            return Result.From(true);
        }

        // 首序
        if (step.PrevStepId is null)
        {
            return Result.From(true);
        }

        // 交换
        // A -> B -> C -> D
        // C 与 B 交换，A.next = C; B.prev = D; B.next = D; C.prev = A; C.next = B; 
        var prevStep = await repo.FirstOrDefaultAsync(m => m.NextStepId == step.Id, cancellationToken);
        if (prevStep == null)
        {
            return Result.From(true);
        }

        List<ProcRoutingStep> steps = [prevStep, step];
        (prevStep.Seq, step.Seq) = (step.Seq, prevStep.Seq); // 交换 seq
     
        // C <=> A
        if (prevStep.PrevStepId is not null)
        {
            var prevStep2 = await repo.FirstOrDefaultAsync(m => m.NextStepId == prevStep.Id, cancellationToken);
            if (prevStep2 != null)
            {
                prevStep2.NextStepId = step.Id;
                steps.Add(prevStep2);
            }
        }

        // B <=> D
        var nextStep = await repo.FirstOrDefaultAsync(m => m.PrevStepId == step.Id, cancellationToken);
        if (nextStep != null)
        {
            nextStep.PrevStepId = prevStep.Id;
            steps.Add(nextStep);
        }

        // C <=> B
        step.PrevStepId = prevStep.PrevStepId;
        prevStep.PrevStepId = step.Id;
        prevStep.NextStepId = step.NextStepId;
        step.NextStepId = prevStep.Id;

        var ok = await repo.UpdateAsync(steps, m => new
        {
            m.Seq,
            m.PrevStepId,
            m.NextStepId,
            m.UpdatedBy,
            m.UpdatedTime,
        }, cancellationToken);
        return Result.From(ok);
    }
}
